/*
 * Created on 2005-3-11
 */
package com.hd123.rumba.domain;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import net.sf.hibernate.FlushMode;
import net.sf.hibernate.Hibernate;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.ObjectNotFoundException;
import net.sf.hibernate.ReplicationMode;
import net.sf.hibernate.type.Type;

import com.hd123.rumba.cartridge.CCartFunctionView;
import com.hd123.rumba.cartridge.ICartFunctionView;
import com.hd123.rumba.exception.BusinessException;
import com.hd123.rumba.exception.DuplicateIdException;
import com.hd123.rumba.exception.ParameterException;
import com.hd123.rumba.log.EntityLogger;
import com.hd123.rumba.runtime.IAfterSaveNew;
import com.hd123.rumba.runtime.IBeforeRemove;
import com.hd123.rumba.runtime.Manager;
import com.hd123.rumba.runtime.NamingMgr;
import com.hd123.rumba.runtime.ObserverRegistry;
import com.hd123.rumba.runtime.OperateContext;
import com.hd123.rumba.sql.ResultPage;
import com.hd123.rumba.sql.SQLSubquery;
import com.hd123.rumba.user.IUserMgr;
import com.hd123.rumba.user.Profile;
import com.hd123.rumba.util.ClassifiedHashtable;
import com.hd123.rumba.util.LevelCode;
import com.hd123.rumba.util.ObjectUtil;

/**
 * @author caili
 */
public class DomainMgr extends Manager implements IDomainMgr {

  public static final String CAPTION_MANAGER = "域管理员";

  private static final String EVENT_ASSIGNCFV = "装载构件包功能视图";
  private static final String EVENT_REMOVECFV = "卸载构件包功能视图";
  private static final String EVENT_UPDATEDFV = "修改域功能视图";

  private static IDomain rootDomain = null;

  public DomainMgr() {
    super();
    this.registryClass("com.hd123.rumba.domain.IDomain", "com.hd123.rumba.domain.Domain");
    this.registryClass("com.hd123.rumba.domain.IDomainFuncView",
        "com.hd123.rumba.domain.DomainFuncView");
  }

  /**
   * 根据层级码找域
   * 
   * @param domain
   *          所属域
   * @param levelCode
   *          层级码
   * @return
   * @throws HibernateException
   */
  public IDomain getDomainByLevelId(IDomain domain, String levelCode) throws HibernateException,
      BusinessException {
    IDomain d = null;
    List list = getSession().find("from IDomain d where d.domain.uuid=? and d.levelId = ?",
        new Object[] {
            domain.getUuid(), levelCode }, new Type[] {
            Hibernate.STRING, Hibernate.STRING });
    if (list.size() > 0)
      d = (IDomain) list.get(0);
    return d;
  }

  /**
   * 创建域
   * 
   * @param parent
   *          可为空
   * @param code
   * @param name
   * @return
   * @throws ParameterException
   * @throws HibernateException
   * @throws DuplicateIdException
   */
  public IDomain createDomain(IDomain parent, String code, String name) throws HibernateException,
      BusinessException {
    checkParameterNotNull(code, "code");
    checkParameterNotNull(name, "name");
    IDomain domain = getDomainByCode(code);
    if (domain != null)
      throw new DuplicateIdException("已经存在code为" + code + "的域");
    domain = new Domain();
    domain.setDomain(parent == null ? domain : getRootDomain());
    domain.setCode(code);
    domain.setName(name);
    domain.setState(CDomain.VALUE_STATE_NORMAL);
    return domain;
  }

  public IDomain getDomain(String uuid) throws HibernateException {
    IDomain domain = null;
    if (uuid != null)
      try {
        domain = (IDomain) getSession().get(IDomain.class, uuid);
      } catch (ObjectNotFoundException e) {
        getLogger().info(e.getMessage());
      }
    return domain;
  }

  public IDomain getValidDomain(String uuid) throws BusinessException, HibernateException {
    checkParameterNotNull(uuid, "uuid");
    IDomain domain = getDomain(uuid);
    if (!CDomain.VALUE_STATE_DELETED.equals(domain.getState()))
      return domain;
    else
      return null;
  }

  public IDomain getDomainByCode(String code) throws HibernateException {
    IDomain domain = null;
    if (code != null) {
      List list = getSession().find(
          "from " + IDomain.class.getName() + " d where d.code = ? and d.state != ?", new Object[] {
              code.toUpperCase(), CDomain.VALUE_STATE_DELETED }, new Type[] {
              Hibernate.STRING, Hibernate.INTEGER });
      if (list.size() > 0)
        domain = (IDomain) list.get(0);
    }
    return domain;
  }

  public IDomain getSupplierByCode(IDomain domain, String code) throws HibernateException,
      BusinessException {
    checkParameterNotNull(domain, "domain");
    checkParameterNotNull(code, "code");
    IDomain supplier = null;
    if (code != null) {
      List list = getSession().find(
          "from IDomain d where d.domain.uuid=? and d.code=? and d.isVendor=? and d.state=?",
          new Object[] {
              domain.getUuid(), code.toUpperCase(), Boolean.TRUE, CDomain.VALUE_STATE_NORMAL },
          new Type[] {
              Hibernate.STRING, Hibernate.STRING, Hibernate.BOOLEAN, Hibernate.INTEGER });
      if (list.size() > 0)
        supplier = (IDomain) list.get(0);
    }
    return supplier;
  }

  /**
   * 保存域. 检查域ID的唯一性. 如果上级单位为空, 置为自己. 如果结算单位为空, 置为上级单位. 根据upperDomain设置层级码.
   * 
   * @param domain
   * @throws HibernateException
   * @throws ParameterException
   * @throws DuplicateIdException
   */
  public void saveDomain(IDomain domain) throws HibernateException, ParameterException,
      DuplicateIdException, BusinessException {
    IUserMgr userMgr = (IUserMgr) NamingMgr.getInstance().lookupMgr(IUserMgr.class);
    saveDomain(domain, new OperateContext(userMgr.getSysUser()), domain.getOca());
  }

  public void saveDomain(IDomain domain, OperateContext operate, long oca)
      throws BusinessException, HibernateException {
    checkParameterNotNull(domain, "domain");
    checkParameterNotNull(operate, "operate");

    ClassifiedHashtable h = checkOca(domain, oca, CDomain.CAPTION_CLASS, domain.getNameCode());
    if (h != null && h.size() > 0)
      throw new BusinessException(h.getAllMessages());

    if (CDomain.VALUE_STATE_DELETED.equals(domain.getState())) {
      ObserverRegistry.notifyObservers(IBeforeRemove.class, domain);
    }

    boolean isNew = domain.getUuid() == null;
    this.checkToSave(domain);

    // 根据upperDomain设置层级码
    // LevelCode lc = new LevelCode(Domain.VALUE_LEVELRULE);
    // Domain upperDomain = domain.getUpperDomain();
    // String levelId = domain.getLevelId();
    // if (upperDomain == null) {
    // if (lc.getLevel(levelId) != 0) {
    // levelId = createLevelId(domain.getDomain(), lc, null);
    // domain.setUpperDomain(domain);
    // }
    // } else if (levelId == null
    // || (!upperDomain.getLevelId().equals(lc.getParent(levelId)) &&
    // !upperDomain.equals(domain)))
    // levelId = createLevelId(domain.getDomain(), lc,
    // upperDomain.getLevelId());
    // domain.setLevelId(levelId);

    Date operTime = operate.getTime();

    EntityLogger logger = new EntityLogger(this);
    logger.setEntity(domain);
    logger.setEntityConstClass(CDomain.class);
    logger.setOperator(operate.getOperator());
    logger.setTime(operTime);

    domain.setLastModified(operTime);
    domain.setLastModifier(operate.getOperator().getNameCode());
    domain.getProfile().setLastModified(domain.getLastModified());
    if (domain.getProfile2() == null)
      domain.setProfile2(new Profile());
    domain.getProfile2().setLastModified(domain.getLastModified());

    // if (domain.getUpperDomain() == null) {
    // domain.setUpperDomain(domain);
    // }
    if (domain.getSettleOrganization() == null) {
      domain.setSettleOrganization(domain.getUpperDomain());
    }

    // 配货次序
    if (domain.getDeliveryOrder() == null)
      domain.setDeliveryOrder(new Integer(0));

    // 设置levelId 2005-8-2
    this.updateDomainLevelId(domain);

    getSession().saveOrUpdate(domain.getProfile());
    getSession().saveOrUpdate(domain.getProfile2());
    getSession().saveOrUpdate(domain.getProfile3());
    getSession().saveOrUpdate(domain.getProfile4());
    getSession().saveOrUpdate(domain);

    // TODO: resetLowerDomainLevelId(domain); 重置下级组织的levelId

    if (isNew)
      ObserverRegistry.notifyObservers(IAfterSaveNew.class, domain);

    if (isNew)
      logger.log(EntityLogger.EVENT_ADDNEW, domain.getState(), domain.getNameCode());
    else
      logger.log(EntityLogger.EVENT_MODIFY, domain.getState(), domain.getNameCode());
  }

  public void saveDomainWithUuid(IDomain domain, OperateContext operate) throws BusinessException,
      HibernateException {
    ObjectUtil.checkParameterNotNull(domain, "domain");
    ObjectUtil.checkParameterNotNull(operate, "operate");

    this.checkToSave(domain);
    Date operTime = operate.getTime();
    EntityLogger logger = new EntityLogger(this);
    logger.setEntity(domain);
    logger.setEntityConstClass(CDomain.class);
    logger.setOperator(operate.getOperator());
    logger.setTime(operTime);

    domain.setLastModified(operTime);
    domain.setLastModifier(operate.getOperator().getNameCode());
    this.updateDomainLevelId(domain);
    if (domain.getProfile() == null)
      domain.setProfile(new Profile());
    if (domain.getProfile2() == null)
      domain.setProfile2(new Profile());
    if (domain.getProfile3() == null)
      domain.setProfile3(new Profile());
    if (domain.getProfile4() == null)
      domain.setProfile4(new Profile());
    getSession().saveOrUpdate(domain.getProfile());
    getSession().saveOrUpdate(domain.getProfile2());
    getSession().saveOrUpdate(domain.getProfile3());
    getSession().saveOrUpdate(domain.getProfile4());

    getSession().replicate(domain, ReplicationMode.OVERWRITE);

    logger.log(EntityLogger.EVENT_MODIFY, domain.getState(), domain.getNameCode());
  }

  public List<IDomain> getDomainsByParent(IDomain domain) throws HibernateException,
      BusinessException {
    this.checkParameterNotNull(domain, "domain");
    List list = getSession().find(
        "from " + IDomain.class.getName()
            + " d where d.state != ? and d.upperDomain.uuid = ? order by d.code", new Object[] {
            CDomain.VALUE_STATE_DELETED, domain.getUuid() }, new Type[] {
            Hibernate.INTEGER, Hibernate.STRING });
    return list;
  }

  /**
   * 查找域domain中的domain, 根据parentLevelId生成新的levelId
   * 
   * @param domain
   * @param lc
   * @param parentLevelId
   *          null表示生成第0级的levelId
   * @return
   */
  public String createLevelId(IDomain domain, LevelCode lc, String parentLevelId)
      throws HibernateException, BusinessException, StringIndexOutOfBoundsException {
    String pattern = lc.getSubLevelIdPattern(parentLevelId);
    List list = getSession().find(
        "select d.levelId from IDomain d where d.domain=? and d.levelId like ?", new Object[] {
            domain.getUuid(), pattern }, new Type[] {
            Hibernate.STRING, Hibernate.STRING });
    return lc.createSubLevelId(parentLevelId, list);
  }

  /**
   * 删除域. 检查是否存在子域.
   * 
   * @param domain
   * @throws HibernateException
   * @throws ParameterException
   * @throws BusinessException
   */
  public void removeDomain(IDomain domain) throws HibernateException, ParameterException,
      BusinessException {
    checkParameterNotNull(domain, "domain");
    int n = createChildDomainsList(domain).size();
    if (n > 0)
      throw new BusinessException("域" + domain.getCode() + "中有" + n + "个子域, 不能删除此域.");
    ObserverRegistry.notifyObservers(IBeforeRemove.class, domain);
    getSession().delete(domain);
  }

  public List createRootDomainsList() throws HibernateException {
    return getSession().find("from IDomain d where d.domain.uuid is null");
  }

  public List createChildDomainsList(IDomain domain) throws HibernateException, BusinessException {
    checkParameterNotNull(domain, "domain");
    return getSession().find("from IDomain d where d.domain.uuid = ?", domain.getUuid(),
        Hibernate.STRING);
  }

  public ResultPage createAllDomainsPage(int pageSize, int page) throws Exception {
    SQLSubquery sq = new SQLSubquery();
    sq.addSelect("d");
    sq.addFrom("IDomain d");
    sq.addOrder("d.code", "asc");
    return ResultPage.createHibernateResultPage(getSession(), sq, pageSize, page);
  }

  /**
   * 取得下级组织.
   * 
   * @param domain
   * @param direct
   *          true表示紧下级组织, false表示所有下级组织.
   * @return List of Domain
   */
  public List getLowerDomains(IDomain domain, boolean direct) throws HibernateException,
      BusinessException {
    LevelCode lc = new LevelCode(CDomain.VALUE_LEVELRULE);
    String pattern;
    if (direct)
      pattern = lc.getSubLevelIdPattern(domain.getLevelId());
    else
      pattern = domain.getLevelId() + "_%";
    SQLSubquery sq = new SQLSubquery();
    sq.addSelect("o");
    sq.addFrom("IDomain o");
    sq.addWhere("o.levelId like ?", pattern);
    sq.addWhere("and o.state=?", CDomain.VALUE_STATE_NORMAL);
    sq.addOrder("o.code");
    ResultPage rp = ResultPage.createHibernateResultPage(getSession(), sq, 0, 0);
    return rp.getContentList();
  }

  public IDomain getRootDomain() throws HibernateException, BusinessException {
    if (rootDomain == null) {
      rootDomain = getDomainByCode(CDomain.VALUE_ID_ROOT);
      if (rootDomain != null) {
        String code = rootDomain.getCode();
      }
    }
    return rootDomain;
  }

  public void clearRootDomainCache() {
    rootDomain = null;
  }

  /**
   * 检查列表中的每个域, 补充从此域到root之间的upperDomain到列表中去. <br>
   * 返回的List就是输入的List, 并且按照domain.levelCode排序
   * 
   * @param domains
   *          List of Domain
   * @return
   */
  public List appendMiddleDomains(List domains) throws HibernateException, BusinessException {
    if (domains == null)
      return null;
    Comparator c = new Comparator() {
      public int compare(Object a, Object b) {
        try {
          return ((IDomain) a).getLevelId().compareTo(((IDomain) b).getLevelId());
        } catch (Exception e) {
          return 0;
        }
      }
    };
    Collections.sort(domains, c);
    int i = 0;
    while (i < domains.size()) {
      IDomain d = (IDomain) domains.get(i);
      IDomain upperDomain = d.getUpperDomain();
      if (upperDomain != null && !domains.contains(upperDomain))
        domains.add(upperDomain);
      ++i;
    }
    Collections.sort(domains, c);
    return domains;
  }

  public ClassifiedHashtable verifyOrganization(IDomain org) throws BusinessException {
    ClassifiedHashtable h = new ClassifiedHashtable();
    if ((org.getIsCompany() == null || !org.getIsCompany().booleanValue())
        && (org.getIsCustomer() == null || !org.getIsCustomer().booleanValue())
        && (org.getIsDc() == null || !org.getIsDc().booleanValue())
        && (org.getIsHeadQuarter() == null || !org.getIsHeadQuarter().booleanValue())
        && (org.getIsStore() == null || !org.getIsStore().booleanValue())
        && (org.getIsVendor() == null || !org.getIsVendor().booleanValue())) {
      h.putMessage("property", ClassifiedHashtable.ERROR, "单位性质没有指定.");
    }
    if (org.getOrderDays() != null && org.getOrderDays().intValue() < 0) {
      h.putMessage("orderDays", ClassifiedHashtable.ERROR, IDomain.CAPTION_ORDERDAYS + "不应小于0");
    }
    if (h.isEmpty())
      return null;
    else
      return h;
  }

  /**
   * 查找域domain中的domain, 取得最新的门店配货次序。最新门店配货次序＝最大门店配货次序 + 10
   * 
   * @param domain
   * @return
   */
  public Integer createNewDeliveryOrder(IDomain domain) throws Exception {
    int deliveryOrder = 0;
    List list = getSession()
        .find(
            "select max(d.deliveryOrder) from IDomain d where d.domain=? and d.isStore = 1 and d.deliveryOrder is not null ",
            domain.getDomain().getUuid(), Hibernate.STRING);

    if (list.size() > 0 && list.get(0) != null) {
      deliveryOrder = ((Integer) list.get(0)).intValue();
    }

    return new Integer(deliveryOrder + 10);
  }

  /**
   * 更新域domain中的domain, 将所有门店的配货次序按原来的顺序，从10,20,...往上重新排序
   * 
   * @param domain
   * @return
   * @deprecated
   */
  public void reOrder(IDomain domain) throws Exception {
    int deliveryOrder = 10;
    IDomain store;
    List list = getSession()
        .find(
            "select d from IDomain d where d.domain=? and d.isStore = 1 and d.levelId like ? order by d.deliveryOrder ",
            new Object[] {
                domain.getDomain().getUuid(), domain.getDomain().getLevelId() + "%" }, new Type[] {
                Hibernate.STRING, Hibernate.STRING });
    if (list.size() > 0) {
      for (int i = 0; i < list.size(); i++) {
        store = (IDomain) list.get(i);
        store.setDeliveryOrder(new Integer(deliveryOrder));
        deliveryOrder = deliveryOrder + 10;
        saveDomain(store);
      }
    }
    return;
  }

  /**
   * 找到指定域下的所有门店
   * 
   * @param upperDomain
   * @return l
   * @throws Exception
   */
  public List getStoreByUpperDomain(IDomain upperDomain) throws Exception {
    List list = new ArrayList();
    list = getSession()
        .find(
            "select d from IDomain d where d.state = 0 and d.isStore = 1 and d.levelId like ? order by d.code ",
            new Object[] {
              upperDomain.getLevelId() + "%" }, new Type[] {
              Hibernate.STRING });
    return list;
  }

  // /////////////////////////
  // About Cartridge

  public List<ICartFunctionView> getCFVsByDomain(IDomain domain) throws BusinessException,
      HibernateException {
    this.checkParameterNotNull(domain, "domain");
    List list = getSession().find(
        "select dfv.funcView from " + lookupClass(IDomainFuncView.class) + " dfv"
            + " where dfv.domain.uuid = ? order by dfv.loadOrder", domain.getUuid(),
        Hibernate.STRING);
    List<ICartFunctionView> cfvs = new ArrayList();
    cfvs.addAll(list);
    return cfvs;
  }

  public boolean hasCFV(IDomain domain, ICartFunctionView cfv) throws BusinessException,
      HibernateException {
    this.checkParameterNotNull(domain, "domain");
    this.checkParameterNotNull(cfv, "cfv");
    List list = getSession().find(
        "from " + lookupClass(IDomainFuncView.class) + " dfv"
            + " where dfv.domain.uuid = ? and dfv.funcView.uuid = ?", new Object[] {
            domain.getUuid(), cfv.getUuid() }, new Type[] {
            Hibernate.STRING, Hibernate.STRING });
    if (list.size() > 0)
      return true;
    else
      return false;
  }

  public void assignCFVToDomain(ICartFunctionView cfv, IDomain domain, OperateContext operate)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(cfv, "cfv");
    this.checkParameterNotNull(domain, "domain");
    this.checkParameterNotNull(operate, "operate");
    if (hasCFV(domain, cfv))
      return;

    IDomainFuncView dfv = new DomainFuncView();
    dfv.setDomain(domain);
    dfv.setFuncView(cfv);
    dfv.setLoadOrder(this.generateLoadOrder(domain));
    dfv.setLastModified(operate.getTime());
    getSession().saveOrUpdate(dfv);
    domain.setLastModified(operate.getTime());
    domain.setLastModifier(operate.getOperator().getNameCode());
    getSession().saveOrUpdate(domain);

    EntityLogger logger = new EntityLogger(this);
    logger.setEntity(domain);
    logger.setEntityConstClass(CDomain.class);
    logger.setOperator(operate.getOperator());
    logger.setTime(operate.getTime());
    logger.log(EVENT_ASSIGNCFV, domain.getState(), CCartFunctionView.CAPTION_CLASS + ": "
        + cfv.getUuid());
  }

  public void removeCFVToDomain(ICartFunctionView cfv, IDomain domain, OperateContext operate)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(cfv, "cfv");
    this.checkParameterNotNull(domain, "domain");
    this.checkParameterNotNull(operate, "operate");
    if (!hasCFV(domain, cfv))
      return;

    getSession().delete(
        "from " + IDomainFuncView.class.getName() + " dfv"
            + " where dfv.domain.uuid = ? and dfv.funcView.uuid = ?", new Object[] {
            domain.getUuid(), cfv.getUuid() }, new Type[] {
            Hibernate.STRING, Hibernate.STRING });
    domain.setLastModified(operate.getTime());
    domain.setLastModifier(operate.getOperator().getNameCode());
    getSession().saveOrUpdate(domain);

    EntityLogger logger = new EntityLogger(this);
    logger.setEntity(domain);
    logger.setEntityConstClass(CDomain.class);
    logger.setOperator(operate.getOperator());
    logger.setTime(operate.getTime());
    logger.log(EVENT_REMOVECFV, domain.getState(), CCartFunctionView.CAPTION_CLASS + ": "
        + cfv.getUuid());
  }

  public void saveDomainFuncView(IDomainFuncView dfv, OperateContext operate)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(dfv, "dfv");
    this.checkParameterNotNull(operate, "operate");

    IDomain domain = dfv.getDomain();

    dfv.setLastModified(operate.getTime());
    getSession().saveOrUpdate(dfv);

    domain.setLastModified(operate.getTime());
    domain.setLastModifier(operate.getOperator().getNameCode());
    getSession().saveOrUpdate(domain);

    EntityLogger logger = new EntityLogger(this);
    logger.setEntity(domain);
    logger.setEntityConstClass(CDomain.class);
    logger.setOperator(operate.getOperator());
    logger.setTime(operate.getTime());
    logger.log(EVENT_UPDATEDFV, domain.getState(), CCartFunctionView.CAPTION_CLASS + ": "
        + dfv.getFuncView().getUuid());
  }

  private Integer generateLoadOrder(IDomain domain) throws BusinessException, HibernateException {
    assert domain != null;
    Integer newOrder = null;
    List list = getSession().find(
        "select max(dfv.loadOrder) from " + IDomainFuncView.class.getName() + " dfv"
            + " where dfv.domain.uuid = ?", domain.getUuid(), Hibernate.STRING);
    if (list.size() > 0)
      newOrder = (Integer) list.get(0);
    if (newOrder == null)
      newOrder = new Integer(0);
    else
      newOrder = new Integer(newOrder.intValue() + 1);
    return newOrder;
  }

  private void checkToSave(IDomain domain) throws BusinessException, HibernateException {
    if (domain.getUuid() != null) {
      getSession().setFlushMode(FlushMode.COMMIT);
      IDomain edomain = getDomainByCode(domain.getCode());
      if (edomain != null && !edomain.getUuid().equals(domain.getUuid()))
        throw new DuplicateIdException("已经存在code为" + domain.getCode() + "的域");
    }
  }

  private void updateDomainLevelId(IDomain domain) throws BusinessException, HibernateException {
    // uuid domain upperDomain levelCode
    // root 自己 =uuid =null =0级单位的层级码
    // 外部单位 自己 =root =null =0级单位的层级码
    // 内部单位 自己 =root =上级单位 =根据upperDomain计算层级码
    LevelCode lc = new LevelCode(CDomain.VALUE_LEVELRULE);
    String levelId = domain.getLevelId();
    if (domain.getDomain() == null || domain.getDomain().equals(domain)) {
      // root
      domain.setUpperDomain(null);
      if (levelId == null || lc.getLevel(levelId) != 0) {
        levelId = createLevelId(domain, lc, null);
        domain.setLevelId(levelId);
      }
    } else if (domain.isInternal()) {
      // 内部单位
      IDomain upperDomain = domain.getUpperDomain();
      if (upperDomain == null) {
        upperDomain = domain.getDomain();
        domain.setUpperDomain(upperDomain);
      }
      if (levelId == null || !upperDomain.getLevelId().equals(lc.getParent(levelId))) {
        levelId = createLevelId(domain.getDomain(), lc, upperDomain.getLevelId());
        domain.setLevelId(levelId);
      }
    } else {
      // 外部单位
      domain.setUpperDomain(null);
      if (levelId == null || lc.getLevel(levelId) != 0) {
        levelId = createLevelId(domain, lc, null);
        domain.setLevelId(levelId);
      }
    }
  }
}
